import java.util.ArrayList;
import java.util.concurrent.CopyOnWriteArrayList;

import processing.core.PApplet;
import processing.core.PConstants;
import processing.core.PFont;
import processing.core.PImage;

public class DeveloperBins {
	private PApplet parent = null;
	private Tooltip tooltip = null;

	private PFont fontBinName = null;
	private PImage defaultImage = null;
	
	private ArrayList<User> userSubmittedBy = null;
	private ArrayList<User> userAssignedTo = null;
	private CopyOnWriteArrayList<User> topSubmittedBy = null;
	private CopyOnWriteArrayList<User> topAssignedTo = null;
	
	private int totalSubmittedByIssues = 1;
	private int totalAssignedToIssues = 1;
	private int anonymousSubmittedByIssues = 1;
	private int anonymousAssignedToIssues = 1;
	
	private boolean clicked = false;
	
	// BG Rect Coordinates and Colors
	private int BGX1 = 0;
	private int BGY1 = 0;
	private int BGX2 = 0;
	private int BGY2 = 0;
	private int BGSTROKE = 0;
	private int BGFILL = 0;
	
	private boolean showBackground = false;
	
	// Text Info
	private int TEXTSTROKE = 0;
	private int TEXTFILL = 0;
	
	// User Info and Coordinates
	private int USERMAX = 0; // calculated
	private int USERMIN = 10;
	private int USERSIZE = 0;
	private int USERSTALL = 0;
	private int USERSPACINGX = 1;
	private int USERSPACINGY = 1;
	private int MAXUSERS = 5;

	private boolean showSubmittedBy = true;
	private boolean showAssignedTo = true;
	
	
	public DeveloperBins(PApplet p, Tooltip t) {
		this.parent = p;
		this.tooltip = t;
		this.defaultImage = this.parent.loadImage("default.jpg");
		this.fontBinName = parent.createFont("FFScala", 12);
		this.userSubmittedBy = new ArrayList<User>();
		this.userAssignedTo = new ArrayList<User>();
		this.topSubmittedBy = new CopyOnWriteArrayList<User>();
		this.topAssignedTo = new CopyOnWriteArrayList<User>();
		setup();
	}
	
	public void setup() {
		// Modify These
		BGSTROKE = parent.color(0,0,255,125);
		BGFILL = parent.color(0,0,255,125);
		TEXTSTROKE = parent.color(255,255,255);
		TEXTFILL = parent.color(255,255,255);
	}
	
	public void update(int x1, int y1, int x2, int y2, boolean show, boolean submittedby, boolean assignedto) {
		// Don't Modify These
		BGX1 = x1;
		BGY1 = y1+fontBinName.theight;
		BGX2 = x2;
		BGY2 = y2;
		showBackground = show;
		showSubmittedBy = submittedby;
		showAssignedTo = assignedto;		
		
		if(MAXUSERS == 0)
			return;

		if(showSubmittedBy && showAssignedTo) {
			USERMAX = (BGX2-BGX1)/2 - 5;
			USERSPACINGX = (BGX2-BGX1)/2;
		} else {
			USERMAX = BGX2-BGX1;
			USERSPACINGX = BGX2-BGX1;
		}

		if(USERMAX < USERMIN)
			USERMAX = USERMIN;
		
		USERSTALL = (BGY2-BGY1)/USERMIN;

		for(int i = USERMAX; i >= USERMIN; i--)
			if( (BGY2-BGY1)/i >= MAXUSERS ) {
				USERSTALL = (BGY2-BGY1)/i;
				USERSIZE = i;
				break;
			}

		if(USERSTALL == 0)
			USERSTALL = 1;
		
		USERSPACINGY = (BGY2-BGY1)/USERSTALL;			
	}

	public void loadUsers(CopyOnWriteArrayList<User> colSubmittedBy, CopyOnWriteArrayList<User> colAssignedTo) {
		userSubmittedBy.clear();
		userAssignedTo.clear();
		for(int i = 0; i < colSubmittedBy.size(); i++)
			userSubmittedBy.add(colSubmittedBy.get(i));
		for(int i = 0; i < colAssignedTo.size(); i++)
			userAssignedTo.add(colAssignedTo.get(i));
	}
	
	public boolean isOver() {
		if(BGX1 <= parent.mouseX && parent.mouseX <= BGX2 && BGY1 <= parent.mouseY && parent.mouseY <= BGY2)
			return true;
		
		return false;
	}
	
	public void isClicked() {
		if(isOver())
			clicked = true;
	}
	
	public void updateUsers() {
		totalSubmittedByIssues = 0;
		anonymousSubmittedByIssues = 0;
		for(User u : userSubmittedBy) {
			totalSubmittedByIssues += u.getIssueCount();
			if(u.getUserName().compareTo("nobod") == 0)
				anonymousSubmittedByIssues = u.getIssueCount();
		}
		
		topSubmittedBy.clear();
		updateTopUsers(topSubmittedBy, userSubmittedBy, totalSubmittedByIssues);

		totalAssignedToIssues = 0;
		anonymousAssignedToIssues = 0;
		for(User u : userAssignedTo) {
			totalAssignedToIssues += u.getIssueCount();
			if(u.getUserName().compareTo("nobod") == 0)
				anonymousAssignedToIssues = u.getIssueCount();
		}	
		
		topAssignedTo.clear();
		updateTopUsers(topAssignedTo, userAssignedTo, totalAssignedToIssues);
	}
	
	private void updateTopUsers(CopyOnWriteArrayList<User> topUsers, ArrayList<User> userList, int max) {
		int curMax = 0;
		User userMax = null;
		
		for(User user : userList)
			if(user.getIssueCount() > curMax && user.getIssueCount() <= max && user.getUserName().compareTo("nobod") != 0 && !topUsers.contains(user)) {
				curMax = user.getIssueCount();
				userMax = user;
			}
		
		if(userMax == null || curMax == 0)
			return;
		
		topUsers.add(userMax);
		
		if(topUsers.size() < MAXUSERS)
			updateTopUsers(topUsers, userList, curMax);
	}

	public void display() {
		parent.rectMode(PConstants.CORNERS);

		// Draw Background
		if(showBackground) {
			parent.stroke(BGSTROKE);
			parent.fill(BGFILL);
			parent.strokeWeight(1);
			parent.rect(BGX1, BGY1, BGX2, BGY2);
		}

		// Draw Users
		parent.strokeWeight(1);
		parent.imageMode(PConstants.CENTER);
		
		double issueSubmittedByCount = 0;
		double issueAssignedToCount = 0;
		for(User u : topSubmittedBy)
			issueSubmittedByCount += u.getIssueCount();
		for(User u : topAssignedTo)
			issueAssignedToCount += u.getIssueCount();
		
		if(issueSubmittedByCount == 0)
			issueSubmittedByCount = 1;
		if(issueAssignedToCount == 0)
			issueAssignedToCount = 1;

		if(showSubmittedBy) {
			parent.textFont(fontBinName);
			parent.textAlign(PConstants.CENTER, PConstants.CENTER);
			parent.stroke(TEXTSTROKE);
			parent.fill(TEXTFILL);
			parent.text("Submitted By", (int)(BGX1+(0.5*USERSPACINGX)), BGY1-fontBinName.theight);

			if(totalSubmittedByIssues > 0) // prevent division by 0
				parent.text(((anonymousSubmittedByIssues*100)/totalSubmittedByIssues)+"% Anonymous", (int)(BGX1+(0.5*USERSPACINGX)), BGY2-fontBinName.theight);

			int i = 0;
			for(User u : topSubmittedBy) {
				if(i >= USERSTALL)
					break;
				
				int x = (int)(BGX1+(0.5*USERSPACINGX));
				int y = (int)(BGY1+((i+0.5)*USERSPACINGY));
				int s = (int)((USERSIZE)*(u.getIssueCount()/issueSubmittedByCount));
				
				if(s > USERMAX)
					s = USERMAX;
				
				// Set Tooltip
				if(!tooltip.isDetails() && x-(s/2) <= parent.mouseX && parent.mouseX <= x+(s/2) && parent.mouseY >= y-(s/2) && parent.mouseY <= y+(s/2)) {
					tooltip.setValue(u);
					if(clicked) {
						tooltip.setLockedValue(u);
						clicked = false;
					}
				}

				// Draw Picture
				if(u.getImage() != null)
					parent.image(u.getImage(), x, y, s, s);
				else if(defaultImage != null)
					parent.image(defaultImage, x, y, s, s);
				
				i++;
			}
		}
		
		if(showAssignedTo) {
			parent.textFont(fontBinName);
			parent.textAlign(PConstants.CENTER, PConstants.CENTER);
			parent.stroke(TEXTSTROKE);
			parent.fill(TEXTFILL);
			parent.text("Assigned To", (int)(BGX1+(((showSubmittedBy ? 1 : 0)+0.5)*USERSPACINGX)), BGY1-fontBinName.theight);			

			if(totalAssignedToIssues > 0) // prevent division by 0
				parent.text(((anonymousAssignedToIssues*100)/totalAssignedToIssues)+"% Anonymous", (int)(BGX1+(((showSubmittedBy ? 1 : 0)+0.5)*USERSPACINGX)), BGY2-fontBinName.theight);

			int i = 0;
			for(User u : topAssignedTo) {
				if(i >= USERSTALL)
					break;
				
				int x = (int)(BGX1+(((showSubmittedBy ? 1 : 0)+0.5)*USERSPACINGX));
				int y = (int)(BGY1+((i+0.5)*USERSPACINGY));
				int s = (int)((USERSIZE)*(u.getIssueCount()/issueAssignedToCount));
				
				// Set Tooltip
				if(!tooltip.isDetails() && x-(s/2) <= parent.mouseX && parent.mouseX <= x+(s/2) && parent.mouseY >= y-(s/2) && parent.mouseY <= y+(s/2)) {
					tooltip.setValue(u);
					if(clicked) {
						tooltip.setLockedValue(u);
						clicked = false;
					}
				}
	
				// Draw Picture
				if(u.getImage() != null)
					parent.image(u.getImage(), x, y, s, s);
				else if(defaultImage != null)
					parent.image(defaultImage, x, y, s, s);
				
				i++;
			}
		}
	}
}